[AGC002F]Leftmost Ball

2020-02-14
Atcoder

题意

$n$种颜色每种各$k$个球排列,每种颜色最左边的球染成白色,问不同颜色序列数

$n,k\leq 2000$

题解

这道题目的idea就是把每种颜色的后k-1个球一起算

令$f_{i,j}$为已经出现了i种颜色,有j个白球的方案,容易知道$i\leq j$

下一个放白球:$f_{i,j}+=f_{i,j-1}$

下一个放别的颜色:$f_{i,j}+=f_{i-1,j}\cdot (n-i+1)\cdot S​$

我们来看在$f_{i-1,j}$的时候后面还有几个位置:$n\cdot k-(i-1)\cdot (k-1)-j$,那么$S=C_{pos-1}^{k-1}$

调试记录

算位置i没-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <cstdio>
#define LL long long
const int maxn = 4e6 + 5;
const int mo = 1e9 + 7;
using namespace std;
LL f[2005][2005], fac[maxn], inv[maxn];
LL C(int n, int m){
if (m == 0 || m == n) return 1;
if (m > n) return 0;
return fac[n] * inv[n - m] % mo * inv[m] % mo;
}
LL pow(LL x, int t){
LL res = 1; x %= mo;
while (t > 0){
if (t & 1) res = res * x % mo;
x = x * x % mo;
t >>= 1;
}
return res;
}
int n, k;
int main(){
scanf("%d%d", &n, &k);
if (k == 1){
puts("1");
return 0;
}
fac[0] = 1;
for (int i = 1; i <= n * k; i++) fac[i] = fac[i - 1] * i % mo;
inv[n * k] = pow(fac[n * k], mo - 2);
for (int i = n * k - 1; i >= 1; i--) inv[i] = inv[i + 1] * (i + 1) % mo;
for (int i = 0; i <= n; i++)
for (int j = i; j <= n; j++){
if (i == 0 && j == 0) f[i][j] = 1;
if (j != 0) f[i][j] = (f[i][j] + f[i][j - 1]) % mo;
if (i != 0) f[i][j] = (f[i][j] + f[i - 1][j] * (n - i + 1) % mo * C(n * k - (i - 1) * (k - 1) - j - 1, k - 2) % mo) % mo;
}
printf("%lld\n", f[n][n]);
return 0;
}